﻿//checked

using System;
using System.Collections.Generic;
using net.entity.framework.common;

namespace net.entity.framework.query {
    public sealed class AliasInfo : IEquatable<AliasInfo> {
        #region Members

        private readonly string catalog;
        private readonly string tableName;
        private readonly Type rootObjType;
        private readonly bool isSafe; //for Nullable
        private readonly string columnPrefix; //for Join
        private readonly AliasInfo joinAliasInfo; //link for Join

        #endregion

        #region Properties

        public string Catalog {
            get { return catalog; }
        }

        public string TableName {
            get { return tableName; }
        }

        public Type RootObjType {
            get { return rootObjType; }
        }

        /// <summary>
        /// Returns true if this AliasInfo returns only non-NULL rows and has not been involved in a CastGuarded
        /// </summary>
        public bool IsSafe {
            get { return isSafe; }
        }

        public string ColumnPrefix {
            get { return columnPrefix; }
        }

        public AliasInfo JoinAliasInfo {
            get { return joinAliasInfo; }
        }

        #endregion

        #region Constructors

        public AliasInfo(string catalog, string tableName, Type rootObjType) {
            this.catalog = catalog;
            this.tableName = tableName;
            this.rootObjType = rootObjType;
            isSafe = true;
            columnPrefix = string.Empty;
            joinAliasInfo = null;
        }

        public AliasInfo(string catalog, string tableName, Type rootObjType, string columnPrefix,
                         AliasInfo joinAliasInfo) {
            this.catalog = catalog;
            this.tableName = tableName;
            this.rootObjType = rootObjType;
            this.joinAliasInfo = joinAliasInfo;
            this.columnPrefix = columnPrefix;
            isSafe = true;
        }

        #endregion

        #region Methods

        public override bool Equals(object obj) {
            var other = obj as AliasInfo;
            return other != null &&
                   Equals(other);
        }

        public bool Equals(AliasInfo other) {
            return other != null &&
                   catalog == other.catalog &&
                   tableName == other.tableName &&
                   rootObjType == other.rootObjType &&
                   isSafe == other.isSafe &&
                   columnPrefix == other.ColumnPrefix &&
                   JoinComparer(this, other);
        }

        internal static bool JoinComparer(AliasInfo lhs, AliasInfo rhs) {
            if (ReferenceEquals(lhs.joinAliasInfo, rhs.joinAliasInfo)) {
                return true;
            }
            return lhs.joinAliasInfo.Equals(rhs.joinAliasInfo);
        }

        internal static bool RootObjectTypeComparer(AliasInfo lhs, AliasInfo rhs) {
            return ReferenceEquals(lhs.JoinAliasInfo.RootObjType, rhs.RootObjType);
        }

        public override int GetHashCode() {
            return Utils.ComputeHashCode(catalog, tableName, rootObjType,
                                         isSafe, columnPrefix, joinAliasInfo);
        }

        #endregion

        #region Nested Class

        public class EqualityComparer : IEqualityComparer<AliasInfo> {
            public static readonly EqualityComparer Default = new EqualityComparer();

            public bool Equals(AliasInfo x, AliasInfo y) {
                // Check whether the compared objects reference the same data.
                if (ReferenceEquals(x, y)) {
                    return true;
                }

                // Check whether any of the compared objects is null.
                if (ReferenceEquals(x, null) || ReferenceEquals(y, null)) {
                    return false;
                }

                // Check whether the products' properties are equal.
                return x.Equals(y);
            }

            public int GetHashCode(AliasInfo obj) {
                return obj.GetHashCode();
            }
        }

        #endregion
    }

    public sealed class AliasKey : IEquatable<AliasKey> {
        public Type RootObjType { get; private set; }

        public AliasKey(Type rootObjType) {
            RootObjType = rootObjType;
        }

        public override bool Equals(object obj) {
            var other = obj as AliasKey;
            return other != null || Equals(other);
        }

        public bool Equals(AliasKey other) {
            return RootObjType == other.RootObjType;
        }

        public override int GetHashCode() {
            return RootObjType.GetHashCode();
        }
    }

    public sealed class AliasValue {
        public string Catalogue { get; private set; }
        public string Table { get; private set; }
        public string AliasName { get; private set; }
        public int TypeId { get; private set; }

        public AliasValue(string catalogue, string table, string aliasName) {
            Catalogue = catalogue;
            Table = table;
            AliasName = aliasName;
        }
    }
}